import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class AlgoVisualizer {

    private static int DELAY = 10;
    private static int blockSide = 8;

    private MazeData data;
    private AlgoFrame frame;

    private static final int d[][] = {{-1,0},{0,1},{1,0},{0,-1}}; // 四个方向移动

	public <String> AlgoVisualizer(String mazeFile){
	    // 初始化数据
        data = new MazeData(mazeFile);

        int sceneHeight = data.N() * blockSide;
        int sceneWidth = data.M() * blockSide;

        // 初始化视图
        EventQueue.invokeLater(() -> {
            frame = new AlgoFrame("Maze Solver Visualization", sceneWidth, sceneHeight);
            frame.addKeyListener(new AlgoKeyListener());
            new Thread(() -> {
                run();
            }).start();
        });
    }

    public void run(){
	    setData(-1, -1, false);

	    data.player = new Position(data.getEntranceX(), data.getEntranceY());

        // 递归实现
        if(!autoGo(data.getEntranceX(), data.getEntranceY()))
            System.out.println("The maze has NO solution!");

        System.out.println("初始化已完成");

	    while (true){
            frame.render(data);
            AlgoVisHelper.pause(DELAY);
            setData(-1, -1, false);

            if (data.player.getX() == data.getExitX() && data.player.getY() == data.getExitY()){
                System.out.println("游戏结束");
                frame.render(data);
                AlgoVisHelper.pause(DELAY);
                break;
            }
        }
	    setData(-1, -1, false);
    }

    // 返回值：求解是否成功
    private boolean autoGo(int x, int y){
        if(!data.inArea(x,y))
            throw new IllegalArgumentException("x,y are out of index in go function!");

        data.visited[x][y] = true;
        setData(x, y, true);

        if (x == data.getExitX() && y == data.getExitY())
            return true;

        for (int i = 0; i < 4; i ++){
            int newX = x + d[i][0];
            int newY = y + d[i][1];
            if (data.inArea(newX, newY) &&
                    data.getMaze(newX, newY) == MazeData.ROAD &&
                    !data.visited[newX][newY]){
                if (autoGo(newX, newY))
                    return true;
            }
        }
        setData(x, y, false);
        return false;
    }

    private void setData(int x, int y, boolean isPath){
	    if (data.inArea(x, y))
            data.path[x][y] = isPath;
    }

    private class AlgoKeyListener extends KeyAdapter{
	    @Override
        public void keyPressed(KeyEvent event){
	        if (event.getKeyCode() == KeyEvent.VK_LEFT){
	            System.out.println("go left");
                oneStep(data.player.getX(), data.player.getY(), 3);
            }
            else if (event.getKeyCode() == KeyEvent.VK_DOWN){
                System.out.println("go down");
                oneStep(data.player.getX(), data.player.getY(), 2);
            }
            else if (event.getKeyCode() == KeyEvent.VK_RIGHT){
                System.out.println("go right");
                oneStep(data.player.getX(), data.player.getY(), 1);
            }
            else if (event.getKeyCode() == KeyEvent.VK_UP){
                System.out.println("go up");
                oneStep(data.player.getX(), data.player.getY(), 0);
            }
            else if (event.getKeyChar() == ' '){
                System.out.println("显示提示");
                data.showPath = !data.showPath;
            }
        }
    }

    private void oneStep(int x, int y, int direction){
        int newX = x + d[direction][0];
        int newY = y + d[direction][1];
        if (data.inArea(newX, newY) &&
                data.getMaze(newX, newY) == MazeData.ROAD){
            data.player.setX(newX);
            data.player.setY(newY);
        }
    }

    public static void main(String[] args) {
        String mazefile = "maze_101_101.txt";
        AlgoVisualizer vis = new AlgoVisualizer(mazefile);
    }
}
